/**
 * 
 */
package net.sahv.bdyz.util;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 张天敏
 * @date 日期：2016年9月7日 时间：上午8:39:56
 */
public class TableInfomationUtil {
	
	public static Connection getConnection() {
		Connection conn = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://192.168.29.65:3306/bdyz";
			String user = "root";
			String pass = "root";
			conn = DriverManager.getConnection(url, user, pass);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
			return conn;
	}
	
	
	

	/**
	 * @author 张天敏
	 * @date 日期：2016年9月7日 时间：上午8:39:56
	 * @param args
	 * @throws SQLException 
	 */
	public static void main(String[] args) throws SQLException {
		
		Connection conn = getConnection();
		
		getTableInfomation(conn);
		
	}




	/**
	 * @author 张天敏
	 * @param conn 
	 * @throws SQLException 
	 * @date 日期：2016年9月7日 时间：下午2:28:18
	 */
	public static Map<String,Object> getTableInfomation(Connection conn) throws SQLException {
		
		//获取某一张数据表中的所有字段的信息
		//getPrepareStatementMethod(conn);
		
		DatabaseMetaData dbmd=conn.getMetaData();
		//获取数据表中的主键
		//getPrimaryKeysMethod(dbmd);
		//循环遍历所有的数据表
		//getTablesMethod(dbmd);
		//获取所有数据表的所有字段信息
		Map<String,Object> map=getAllTablesAllColumns(dbmd,conn);
		
		return map;
	}




	/**
	 * @author 张天敏
	 * @date 日期：2016年9月7日 时间：下午5:07:06
	 * @param dbmd
	 * @param conn 
	 * @throws SQLException 
	 */
	private static Map<String,Object> getAllTablesAllColumns(DatabaseMetaData dbmd, Connection conn) throws SQLException {
		
		
		
		List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
		Map<String,String> mapTabelMark=getTablesMethod(dbmd);
		 
		ResultSet rs4=dbmd.getColumns(null,"%", "%", "%");
		while (rs4.next()) {
			
			String TABLE_NAME = rs4.getString("TABLE_NAME");          //table name
			
			String sql2 = "SHOW CREATE TABLE "+TABLE_NAME;
			PreparedStatement stmt;
			stmt = conn.prepareStatement(sql2);
			ResultSet rs = stmt.executeQuery();
			String tableComment="";
			while(rs.next()){
				String createTable=rs.getString("Create Table");
				int lastIndexOfComment=createTable.lastIndexOf("COMMENT");
				String comment="COMMENT";
				if(lastIndexOfComment>0){
					//获取表的备注字段信息
					tableComment=createTable.substring(lastIndexOfComment+2+comment.length(), createTable.length()-1);
					System.out.println(tableComment);
				}
			}
            
            String tableMark=mapTabelMark.get("TABLE_NAME");
            System.out.println(tableMark+"11111111111111");
            String COLUMN_NAME = rs4.getString("COLUMN_NAME");       // column name 
            String REMARKS = rs4.getString("REMARKS");               //comment describing column (may be null) 
            String TYPE_NAME = rs4.getString("TYPE_NAME");           //Data source dependent type name, for a UDT the type name is fully qualified 
            String COLUMN_SIZE = rs4.getString("COLUMN_SIZE");       //column size.
            String columnDef = rs4.getString("COLUMN_DEF");           //默认值 
            int charOctetLength = rs4.getInt("CHAR_OCTET_LENGTH");   //char类型的列中的最大字节数  
            int ordinalPosition = rs4.getInt("ORDINAL_POSITION");  //表中列的索引（从1开始） 
            
            String[] tableNames=TABLE_NAME.split("_");
            String tableHead=tableNames[0];
            if(tableHead.equals("d")){     //如果是以头部d_开头的数据表，则直接略过
            	
            }else{         //非头部以d_开头的数据表则进行后续的操作
                System.out.println(TABLE_NAME);
                String typeNameXml="";
                if(TYPE_NAME.equals("INT")){
                	typeNameXml="INTEGER";
                }else{
                	typeNameXml=TYPE_NAME;
                }
                //将备注字段进行切割，前面的用作备注，后面的用作json串处理
                String[] remarkString=REMARKS.split("\\|");
                
            	Map<String,Object> map=new HashMap<String,Object>();
            	map.put("tableName", TABLE_NAME);
            	map.put("tableCommentAll", tableComment);
            	String[] tableCommentAllArray=tableComment.split("\\|");
            	map.put("tableComment", tableCommentAllArray[0]);
            	if(tableCommentAllArray.length>1){
            		map.put("tableCommentCommond", tableCommentAllArray[1]);
            	}else{
            		map.put("tableCommentCommond", "");
            	}
            	map.put("columnName", COLUMN_NAME);
            	map.put("remarkAll", REMARKS);
            	map.put("REMARKS", remarkString[0]);
            	if(remarkString.length>1){
            		//再次进行字符串分割,例如：select:1:男-2:女
            		String[] remarkStringArray=remarkString[1].split("\\:", 2);
            		//例如：select
            		map.put("remarkStringKey", remarkStringArray[0]);
            		if(remarkStringArray.length>1){
            			List<Map<String,String>> listValue=splitToList(remarkStringArray[1]);
            			map.put("remarkStringValue", listValue);
            		}else{
            			//比如说param
            			map.put("remarkStringValue", "input");
            		}
            		
            	}else{
            		map.put("remarkStringKey", "input");
            	}
            	
            	map.put("typeName", TYPE_NAME);         //mysql中字段的数据类型
            	map.put("typeNameXml", typeNameXml);   //mapper.xml文件中字段的数据类型
            	map.put("COLUMN_SIZE", COLUMN_SIZE);
            	map.put("columnDef", columnDef);
            	map.put("charOctetLength", charOctetLength);
            	map.put("ordinalPosition", ordinalPosition);    //字段的索引值
            	
            	//将数据库中字段的类型转换成Java中的数据类型
            	String typeName=changeDataType(TYPE_NAME);
            	map.put("TYPE_NAME", typeName);        //实体类中字段的数据类型
            	
            	//将数据库字段中的大小字母转换成首字母小写的驼峰命名法
            	String columnName=changeColumnName(COLUMN_NAME);
            	map.put("COLUMN_NAME", columnName);
            	
            	//将数据表名修改成驼峰命名法
            	TABLE_NAME=changeTableName(TABLE_NAME);
            	map.put("TABLE_NAME", TABLE_NAME);
            	
            	list.add(map);
            	//System.out.println(TABLE_NAME+"|"+COLUMN_NAME+"|"+REMARKS+"|"+TYPE_NAME+"|"+COLUMN_SIZE+"|"+columnDef+"|"+charOctetLength+"|"+ordinalPosition);
            }
            
		}
		boolean flag=false;
		Map<String,Object> mapObj=new HashMap<String,Object>();
		for(Map<String,Object> listOne:list){
			//获取字段的索引号
			int ordinalPosition=(int) listOne.get("ordinalPosition");
			//获取数据表名
			String TABLE_NAME=(String) listOne.get("TABLE_NAME");
			if(ordinalPosition==1){
				List<Map<String,Object>> list2=new ArrayList<Map<String,Object>>();
				for(Map<String,Object> listOne2:list){
					String TABLE_NAME2=(String) listOne2.get("TABLE_NAME");
					if(TABLE_NAME.equals(TABLE_NAME2)){
						list2.add(listOne2);
					}
				}
				
				mapObj.put(TABLE_NAME, list2);
			}
		}
		
		return mapObj;
	}

	/**
	 * @author 张天敏
	 * @date 日期：2016年9月10日 时间：下午1:57:03
	 * @param string
	 * @return
	 */
	private static List<Map<String, String>> splitToList(String string) {
		List<Map<String,String>> list=new ArrayList<Map<String,String>>();
		//数据格式类似于：1:男-2:女
		String[] jsonString=string.split("-");
		//数据格式类似于:  1:男
		for(int i=0,stringLength=jsonString.length;i<stringLength;i++){
			Map<String,String> map=new HashMap<String,String>();
			String[] proString=jsonString[i].split("\\:");
			map.put("keyString", proString[0]);
			map.put("valueString", proString[1]);
			list.add(map);
		}
		return list;
	}




	/**
	 * @author 张天敏
	 * @date 日期：2016年9月8日 时间：下午3:45:49
	 * @param tABLE_NAME
	 * @return
	 */
	public static String changeTableName(String TABLE_NAME) {
		//将文字转换成小写
		TABLE_NAME=TABLE_NAME.toLowerCase();
    	//将字符串分割成数组
    	String[] columnNames=TABLE_NAME.split("_");
    	String tempString="";
    	for(int i=0,columnCount=columnNames.length;i<columnCount;i++){
    		//首字母大写
			tempString+=columnNames[i].substring(0, 1).toUpperCase()+columnNames[i].substring(1, columnNames[i].length());                    
    	}
    	
		return tempString;
	}




	/**
	 * 将数据库字段中的大小字母转换成首字母小写的驼峰命名法
	 * @author 张天敏
	 * @date 日期：2016年9月8日 时间：下午3:40:40
	 * @param cOLUMN_NAME
	 * @return
	 */
	private static String changeColumnName(String COLUMN_NAME) {
		//将文字转换成小写
    	COLUMN_NAME=COLUMN_NAME.toLowerCase();
    	//将字符串分割成数组
    	String[] columnNames=COLUMN_NAME.split("_");
    	String tempString="";
    	for(int i=0,columnCount=columnNames.length;i<columnCount;i++){
    		if(i==0){   //首字母要小写，所以说不用做处理
    			tempString+=columnNames[i];
    		}else{    //如果不是单词的首字母，那么则进行首字母大写转换
    			tempString+=columnNames[i].substring(0, 1).toUpperCase()+columnNames[i].substring(1, columnNames[i].length());                    
    		}
    	}
    	
		return tempString;
	}




	/**
	 * 将数据库中字段的类型转换成Java中的数据类型
	 * @author 张天敏
	 * @date 日期：2016年9月8日 时间：下午3:37:46
	 * @param tYPE_NAME
	 * @return 
	 */
	private static String changeDataType(String TYPE_NAME) {
		//将数据库中字段的类型转换成Java中的数据类型
    	if(TYPE_NAME.equals("TEXT")||TYPE_NAME.equals("TINYTEXT")||TYPE_NAME.equals("VARCHAR")){
    		TYPE_NAME="String";
    	}else if(TYPE_NAME.equals("INT")){
    		TYPE_NAME="int";
    	}else if(TYPE_NAME.equals("TIMESTAMP")||TYPE_NAME.equals("DATETIME")){
    		TYPE_NAME="Date";
    	}else if(TYPE_NAME.equals("DECIMAL")){
    		TYPE_NAME="BigDecimal";
    	}
		return TYPE_NAME;
	}




	/**
	 * @author 张天敏
	 * @date 日期：2016年9月7日 时间：下午4:59:36
	 * @param conn
	 * @throws SQLException 
	 */
	private static void getPrepareStatementMethod(Connection conn) throws SQLException {
		
		String sql = "select * from address";
		String sql2 = "SHOW CREATE TABLE `aa`";
		PreparedStatement stmt;
		stmt = conn.prepareStatement(sql2);
		ResultSet rs = stmt.executeQuery();
		
		while(rs.next()){
			String createTable=rs.getString("Create Table");
			int lastIndexOfComment=createTable.lastIndexOf("COMMENT");
			//int COMMENTIndex=createTable.indexOf("COMMENT");
			String comment="COMMENT";
			String commentString=createTable.substring(lastIndexOfComment+2+comment.length(), createTable.length()-1);
			System.out.println(commentString);
		}
		
		ResultSetMetaData data = rs.getMetaData();
		for (int i = 1; i <= data.getColumnCount(); i++) {
		
			// 获得所有列的数目及实际列数
			int columnCount = data.getColumnCount();
			// 获得指定列的列名
			String columnName = data.getColumnName(i);
			// 获得指定列的列值
			int columnType = data.getColumnType(i);
			// 获得指定列的数据类型名
			String columnTypeName = data.getColumnTypeName(i);
			// 所在的Catalog名字
			String catalogName = data.getCatalogName(i);
			// 对应数据类型的类
			String columnClassName = data.getColumnClassName(i);
			// 在数据库中类型的最大字符个数
			int columnDisplaySize = data.getColumnDisplaySize(i);
			// 默认的列的标题
			String columnLabel = data.getColumnLabel(i);
			// 获得列的模式
			String schemaName = data.getSchemaName(i);
			// 某列类型的精确度(类型的长度)
			int precision = data.getPrecision(i);
			// 小数点后的位数
			int scale = data.getScale(i);
			// 获取某列对应的表名
			String tableName = data.getTableName(i);
			// 是否自动递增
			boolean isAutoInctement = data.isAutoIncrement(i);
			// 在数据库中是否为货币型
			boolean isCurrency = data.isCurrency(i);
			// 是否为空
			int isNullable = data.isNullable(i);
			// 是否为只读
			boolean isReadOnly = data.isReadOnly(i);
			// 能否出现在where中
			boolean isSearchable = data.isSearchable(i);
			System.out.println(columnCount);
			System.out.println("获得列" + i + "的字段名称:" + columnName);
			System.out.println("获得列" + i + "的类型,返回SqlType中的编号:"+ columnType);
			System.out.println("获得列" + i + "的数据类型名:" + columnTypeName);
			System.out.println("获得列" + i + "所在的Catalog名字:"+ catalogName);
			System.out.println("获得列" + i + "对应数据类型的类:"+ columnClassName);
			System.out.println("获得列" + i + "在数据库中类型的最大字符个数:"+ columnDisplaySize);
			System.out.println("获得列" + i + "的默认的列的标题:" + columnLabel);
			System.out.println("获得列" + i + "的模式:" + schemaName);
			System.out.println("获得列" + i + "类型的精确度(类型的长度):" + precision);
			System.out.println("获得列" + i + "小数点后的位数:" + scale);
			System.out.println("获得列" + i + "对应的表名:" + tableName);
			System.out.println("获得列" + i + "是否自动递增:" + isAutoInctement);
			System.out.println("获得列" + i + "在数据库中是否为货币型:" + isCurrency);
			System.out.println("获得列" + i + "是否为空:" + isNullable);
			System.out.println("获得列" + i + "是否为只读:" + isReadOnly);
			System.out.println("获得列" + i + "能否出现在where中:"+ isSearchable);
			
		}
	}

	/**
	 * @author 张天敏
	 * @date 日期：2016年9月7日 时间：下午4:57:02
	 * @param dbmd
	 * @return 
	 * @throws SQLException 
	 */
	private static Map<String, String> getTablesMethod(DatabaseMetaData dbmd) throws SQLException {
		//循环遍历所有的数据表
		// table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".  
		String[] types = { "TABLE" };
		Map<String,String> map=new HashMap<String,String>();
		ResultSet rs3=dbmd.getTables(null, null, "%", types);
		while (rs3.next()) {
			
                String tableName = rs3.getString("TABLE_NAME");  //表名  
                String tableType = rs3.getString("TABLE_TYPE");  //表类型  
                String remarks = rs3.getString("REMARKS");       //表备注  
                //System.out.println(tableName + "-" + tableType + "-" + remarks);
                String TABLE_SCHEM=rs3.getString("TABLE_SCHEM");
                
                map.put(tableName, remarks);
                System.out.println(tableName+remarks+"222222222222222");
        }
		return map;
	}




	/**
	 * @author 张天敏
	 * @date 日期：2016年9月7日 时间：下午4:55:44
	 * @param dbmd
	 * @throws SQLException 
	 */
	private static void getPrimaryKeysMethod(DatabaseMetaData dbmd) throws SQLException {
		// TODO Auto-generated method stub
		ResultSet rs2=dbmd.getPrimaryKeys(null, null, "address");
		//获取与主键相关的信息，由于一张数据表一般只有一个主键，所以说获取的结果集也就是只有一条信息而已
		while (rs2.next()) {  
            String tableName = rs2.getString("COLUMN_NAME");       //字段名       column name 
            String primaryKeyName = rs2.getString("PK_NAME");      //primary key name (may be null) 
            String tableNameRs2 = rs2.getString("TABLE_NAME");     //table name 
            String TABLE_CAT = rs2.getString("TABLE_CAT");       //table catalog (may be null)
            String TABLE_SCHEM = rs2.getString("TABLE_SCHEM");      //table schema (may be null)
            System.out.println(tableName+"|"+primaryKeyName+"|"+tableNameRs2+"|"+TABLE_CAT+"|"+TABLE_SCHEM);
        }
	}

}
